package com.learn.sb.redis.reids.demo;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;

/**
 * 使用Redis事务
 * redis 的事务 通常是一个命令组合 watch...multi...exec
 * 也就是要在一个Redis连接中执行多个命令，考虑用 SessionCallback 实现
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class RedisTransactionDemo {

	@Autowired
	private StringRedisTemplate redisTemplate;

	@Test
	public void testMulti() {
		redisTemplate.opsForValue().set("key1", "value");

		List list = redisTemplate.execute(new SessionCallback<List>() {
			@Override
			public List execute(RedisOperations redisOperations) throws DataAccessException {
				// 设置要监控 key1
				redisOperations.watch("key1");
				// 开启事务，在exec命令执行前，全部都只是进入队列
				redisOperations.multi();
				redisOperations.opsForValue().set("key2", "value2");

				// key1的值是字符串，+1 肯定抛出异常，不过，抛出异常后，后面的key2 和 key3 仍然会执行成功
				// redisOperations.opsForValue().increment("key1", 1);

				Object value2 = redisOperations.opsForValue().get("key2");
				System.out.println("命令在队列，所以 value2 的值为 null。" + value2);
				redisOperations.opsForValue().set("key3", "value3");
				Object value3 = redisOperations.opsForValue().get("key3");
				System.out.println("命令在队列，所以 value3 的值为 null。" + value3);
				// 先判断 key1 在watch命令监控后是否被修改过，
				// 如果被修改过，则不执行事务
				// 如果没被修改过，则执行事务
				return redisOperations.exec();
			}
		});

		System.out.println(list);
	}
}
